package org.flexspeedup.control
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;

import mx.core.IMXMLObject;

import org.swizframework.core.IDispatcherAware;
import org.swizframework.utils.chain.CommandChain;
import org.swizframework.utils.chain.IChainStep;
import org.swizframework.utils.chain.CommandChainStep;
import org.swizframework.events.ChainEvent;
import org.flexspeedup.utils.SwizDispatcherBase;

[Event( name="chainStart",			type="org.swizframework.events.ChainEvent" )]
[Event( name="chainStepComplete",	type="org.swizframework.events.ChainEvent" )]
[Event( name="chainStepError",		type="org.swizframework.events.ChainEvent" )]
[Event( name="chainComplete",		type="org.swizframework.events.ChainEvent" )]
[Event( name="chainFail",			type="org.swizframework.events.ChainEvent" )]

[DefaultProperty("chainMembers")]
/**
 * Provides a way to create a command chain and control it from the a bean loader.
 */
public class CommandChainController extends SwizDispatcherBase implements IMXMLObject
{
    //--------------------------------------------------------------------------
    //
    // Constructor
    //
    //--------------------------------------------------------------------------

    /**
     * Creates a new instance of this class.
     */
    public function CommandChainController()
    {
    }
    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------
    
    //----------------------------------
    //  commandChain
    //----------------------------------
    /**
     *  @private
     */
    private var commandChain:CommandChain;
    
    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  chainMembers
    //----------------------------------
    /**
     *  @private
     */    
    private var _chainMembers:Array /* of CommandChainStep */;
    
    /**
     * An array containing the <code>CommandChainStep</code> instances.
     * @see org.swizframework.utils.chain.CommandChainStep
     */
    public function get chainMembers():Array /* of CommandChainStep */
    {
        return _chainMembers;
    }
    
    public function set chainMembers(value:Array /* of CommandChainStep */):void
    {
        if (value == null)
            return;
        
        _chainMembers = value;
    }

    //--------------------------------------------------------------------------
    //
    //  Methods - IMXMLObject
    //
    //--------------------------------------------------------------------------  

    /**
     * @inheritDoc mx.core.IMXMLObject
     */  
    public function initialized(document:Object, id:String):void
    {
    }

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

    /**
     * Starts the <code>commandChain</code>
     * <p> Override this method, and [Mediate...] it to start the command chain
     * using custom events.</p>
     * <p> In order to handle chain events, you should listen to the following
     * events in the <code>CommmandChainController</code> subclasses:</p>
     * <ul>
     * <li><code>"chainStarted"</code></li>
     * <li><code>"chainStepComplete"</code></li>
     * <li><code>"chainStepError"</code></li>
     * <li><code>"chainComplete"</code></li>
     * <li><code>"chainFailure"</code></li>
     * </ul>
     */
    public function start():void
    {
        commandChain = new CommandChain();
        
        for each(var chainMember:CommandChainStep in _chainMembers)
            commandChain.addCommand(chainMember);
        
        commandChain.addEventListener(
            ChainEvent.CHAIN_START, commandChain_chainStartHandler);
        commandChain.addEventListener(
            ChainEvent.CHAIN_STEP_COMPLETE, commandChain_chainStepCompleteHandler);
        commandChain.addEventListener(
            ChainEvent.CHAIN_COMPLETE, commandChain_chainCompleteHandler);
        commandChain.addEventListener(
            ChainEvent.CHAIN_STEP_ERROR, commandChain_chainStepErrorHandler);
        commandChain.addEventListener(
            ChainEvent.CHAIN_FAIL, commandChain_chainFailHandler);
        
        commandChain.start();
    }
    
    /**
     *  @private
     */
    private function removeEventListeners():void
    {
        commandChain.removeEventListener(
            ChainEvent.CHAIN_START, commandChain_chainStartHandler);
        commandChain.removeEventListener(
            ChainEvent.CHAIN_STEP_COMPLETE, commandChain_chainStepCompleteHandler);
        commandChain.removeEventListener(
            ChainEvent.CHAIN_COMPLETE, commandChain_chainCompleteHandler);
        commandChain.removeEventListener(
            ChainEvent.CHAIN_STEP_ERROR, commandChain_chainStepErrorHandler);
        commandChain.removeEventListener(
            ChainEvent.CHAIN_FAIL, commandChain_chainFailHandler);
    }
    
    //--------------------------------------------------------------------------
    //
    //  Event Handlers
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    private function commandChain_chainStartHandler(event:Event):void
    {
        dispatchEvent(event.clone());
    }

    /**
     *  @private
     */
    private function commandChain_chainStepCompleteHandler(event:Event):void
    {
        dispatchEvent(event.clone());
    }

    /**
     *  @private
     */
    private function commandChain_chainStepErrorHandler(event:Event):void
    {
        dispatchEvent(event.clone());
        removeEventListeners();
    }

    /**
     *  @private
     */
    private function commandChain_chainCompleteHandler(event:Event):void
    {
        dispatchEvent(event.clone());
        removeEventListeners();
    }

    /**
     *  @private
     */
    private function commandChain_chainFailHandler(event:Event):void
    {
        dispatchEvent(event.clone());
        removeEventListeners();
    }
    
}
}